package com.lwd.utils;


import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

/**
 * hugui
 */
public class DateUtil {

    public static final String YMD_HMS = "yyyy-MM-dd HH:mm:ss";

    public static final String YMD = "yyyy-MM-dd";

    public static final String YM = "yyyy-MM";

    public static final long ONE_DAY_MillIS = 24 * 60 * 60 * 1000;

    private static ThreadLocal<DateFormat> threadLocalDateFormat(final String pattern) {
        ThreadLocal<DateFormat> tl = new ThreadLocal<DateFormat>() {
            protected DateFormat initialValue() {
                return new SimpleDateFormat(pattern);
            }
        };
        return tl;
    }
    private static Map<String, ThreadLocal<DateFormat>> tlDateFormatMap = new ConcurrentHashMap<String, ThreadLocal<DateFormat>>();

    public static DateFormat getDateFormat(String fmt){
        ThreadLocal<DateFormat> tl = tlDateFormatMap.get(fmt);
        if(tl == null){
            tl = threadLocalDateFormat(fmt);
            tlDateFormatMap.put(fmt, tl);
        }
        return tl.get();
    }

    private static Map<Pattern, String> regPatternMap = new HashMap<Pattern, String>();

    static {
        regPatternMap.put(Pattern.compile("^\\d{4}-\\d{1,2}-\\d{1,2}$"), "yyyy-MM-dd");
        regPatternMap.put(Pattern.compile("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$"), "yyyy-MM-dd HH:mm:ss");
        regPatternMap.put(Pattern.compile("^\\d{4}\\d{1,2}\\d{1,2}$"), "yyyyMMdd");
        regPatternMap.put(Pattern.compile("^\\d{4}\\d{1,2}$"), "yyyyMM");
        regPatternMap.put(Pattern.compile("^\\d{4}/\\d{1,2}/\\d{1,2}$"), "yyyy/MM/dd");
        regPatternMap.put(Pattern.compile("^\\d{4}年\\d{1,2}月\\d{1,2}日$"), "yyyy年MM月dd日");
        regPatternMap.put(Pattern.compile("^\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$"), "yyyy/MM/dd HH:mm:ss");
        regPatternMap.put(Pattern.compile("^\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}\\.\\d{1}$"), "yyyy/MM/dd HH:mm:ss.S");
        regPatternMap.put(Pattern.compile("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}\\.\\d{1}$"), "yyyy-MM-dd HH:mm:ss.S");
    }

    public static Date addMonth(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, interval);
        return calendar.getTime();
    }

    public static Date decMonth(Date date, int interval) {
        return addMonth(date, -1 * interval);
    }

    public static Date addDay(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, interval);
        return calendar.getTime();
    }

    public static Date addHour(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, interval);
        return calendar.getTime();
    }

    public static Date addMinute(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, interval);
        return calendar.getTime();
    }

    public static Date decDay(Date date, int interval) {
        return addDay(date, -1 * interval);
    }

    public static Date addSecond(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.SECOND, interval);
        return calendar.getTime();
    }

    /**
     * 方法描述： 根据传入的时间，返回与之 年份/月份/日期/小时/分钟/秒 相距interval的时间
     */
    public static Date getDate(long millis, int fileds, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millis);
        calendar.add(fileds, interval);
        return calendar.getTime();
    }

    public static Date convert(Long timestamp){
        return new Date(timestamp);
    }

    /**
     * 方法描述：获取当前时间的
     */
    public static Date now() {
        return new Date();
    }

    public static Long currentTimeMillis(){
        return System.currentTimeMillis();
    }
    /**
     * 方法描述：获取前一天的结束时间
     */
    public static Date getYesterdayNight() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, -1);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    public static Date getYesterdayNight(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DATE, -1);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 方法描述：获取当日的最晚时间
     *
     * @author: guanfu.xie
     * @version: Dec 27, 2010 4:48:35 PM
     */
    public static Date getDayNight(String dateStr, String pattern) {
        Date date = null;
        if (StringUtils.isNotEmpty(dateStr)) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                date = sdf.parse(dateStr);
                Calendar c = Calendar.getInstance();
                c.setTime(date);
                c.set(Calendar.HOUR_OF_DAY, 23);
                c.set(Calendar.MINUTE, 59);
                c.set(Calendar.SECOND, 59);
                date = c.getTime();
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return date;
    }

    /**
     * 得到两个时间之间相差的天数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getDaysBetween(Date startDate, Date endDate) {
        return (int) ((endDate.getTime() - startDate.getTime()) / ONE_DAY_MillIS);
    }

    /**
     * 方法描述：获取当日的最晚时间
     */
    public static Date getDayNight(Date dateTime) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        Date date = c.getTime();
        return date;
    }

    /**
     * 方法描述：  距当前时间的 interval 天的晚上(23点59分59秒);
     */
    public static Date getDayNight(Date dateTime, int interval) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.DATE, interval);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        Date date = c.getTime();
        return date;
    }

    /**
     * 方法描述：获取当日的最早时间
     */
    public static Date getDayMorning(String dateStr, String pattern) {
        Date date = null;
        if (StringUtils.isNotEmpty(dateStr)) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                date = sdf.parse(dateStr);
                Calendar c = Calendar.getInstance();
                c.setTime(date);
                c.set(Calendar.HOUR_OF_DAY, 0);
                c.set(Calendar.MINUTE, 0);
                c.set(Calendar.SECOND, 0);
                c.set(Calendar.MILLISECOND, 0);
                date = c.getTime();
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return date;
    }


    /**
     * 方法描述：获取当日的最早时间
     */
    public static Date getDayMorning(Date dateTime) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        Date date = c.getTime();
        return date;
    }

    /**
     * 方法描述：几天之前/后的早上(0点0分0秒)
     */
    public static Date getDayMorning(Date dateTime, int interval) {
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.DATE, interval);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        Date date = c.getTime();
        return date;
    }

    /**
     * 方法描述： date 在 firstHour 和 endHour点钟之间返回true
     */
    public static boolean isNight(Date date, int firstHour, int endHour) {
        boolean flag = false;
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        if (hour >= firstHour && hour <= endHour) {
            flag = true;
        }
        return flag;
    }

    /**
     * 方法描述：判断一个时间是否在某个时间段内
     */
    public static boolean isIn(Date date, Date startDate, Date endDate) {
        if (!date.before(startDate) && !date.after(endDate)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 方法描述：对输入的时间换算为几时几分几秒几毫秒
     */
    public static String format2HMS(long duration) {
        long ms = duration % 1000;
        long s = duration / 1000;
        long m = s / 60;
        s = s % 60;
        long h = m / 60;
        m = m % 60;
        return h + "小时" + m + "分钟" + s + "秒" + ms + "毫秒";
    }

    /**
     * 方法描述：格式化日期
     */
    public static String formatDate(Date d, String fmt) {
        return getDateFormat(fmt).format(d);
    }

    public static String formatYMD(Date d) {
        return getDateFormat(YMD).format(d);
    }

    public static String formatYMD_HMS(Date d) {
        return getDateFormat(YMD_HMS).format(d);
    }

    /**
     * 方法描述：格式化日期
     */
    public static String formatDate(Long date, String fmt) {
        return getDateFormat(fmt).format(date);
    }

    /**
     * 方法描述：该月的第一天
     */
    public static Date getMonthFirstDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        return c.getTime();
    }

    /**
     * 生成指定时期日期对象
     * @return
     */
    public static Date getDate(int year, int month, int day, int hour, int minite, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, day, hour, minite, second);
        return calendar.getTime();
    }

    /**
     * 获取当月已经经过的天数
     *
     * @return
     */
    public static int getCurrentMonthDays() {
        Calendar aCalendar = Calendar.getInstance();
        aCalendar.setTime(getMonthFirstDay(now()));
        int day1 = aCalendar.get(Calendar.DAY_OF_YEAR);
        aCalendar.setTime(now());
        int day2 = aCalendar.get(Calendar.DAY_OF_YEAR);
        return day2 - day1;
    }

    /**
     * 获取指定日期所在月份已经经过的天数
     *
     * @return
     */
    public static int getMonthDays(Date date) {
        Calendar aCalendar = Calendar.getInstance();
        aCalendar.setTime(getMonthFirstDay(date));
        int day1 = aCalendar.get(Calendar.DAY_OF_YEAR);
        aCalendar.setTime(date);
        int day2 = aCalendar.get(Calendar.DAY_OF_YEAR);
        return day2 - day1;
    }

    /**
     * 是否在同一个月
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameMonth(Date date1, Date date2) {
        DateFormat df = getDateFormat(YM);
        String month1 = df.format(date1);
        String month2 = df.format(date2);
        return month1.equals(month2);
    }

    /**
     * 方法描述：判断两个时间相差多少个月
     *
     * @author: Think
     * @version: 2011-11-4 下午01:25:49
     */
    public static int monthDiff(Date gmtExpired, Date gmtCreate) {
        if (gmtCreate == null || gmtExpired == null) {
            return 0;
        }
        int day = dateDiff(gmtExpired, gmtCreate);
        int monthDiff = 0;
        double INIT_DAY = 30;
        if (day > 0) {
            monthDiff = (int) Math.ceil(day / INIT_DAY);
        }
        return monthDiff;
    }

    /**
     * 返回两个日期之间隔了多少天
     *
     * @param date1
     * @param date2
     */
    public static int dateDiff(Date date1, Date date2) {
        int i = (int) ((date1.getTime() - date2.getTime()) / 3600 / 24 / 1000);
        return i;
    }

    /**
     * 获取当月第一天的0点0分0秒
     *
     * @return java.util.Date
     */
    public static Date getMonthStart() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        return c.getTime();
    }

    public static int getDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    public static Date getPatternDate(Date date, String pattern) {
        String dateString = formatDate(date, pattern);
        return parse(dateString, pattern);
    }

    /**
     * 重置日期的秒数为amount并返回
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date setSeconds(Date date, int amount) {
        return set(date, Calendar.SECOND, amount);
    }

    /**
     * 重置日期的小时数为amount并返回
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date setHours(Date date, int amount) {
        return set(date, Calendar.HOUR_OF_DAY, amount);
    }

    /**
     * 重置日期的天数为amount并返回
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date setDays(Date date, int amount) {
        return set(date, Calendar.DAY_OF_MONTH, amount);
    }

    /**
     * 重置日期的月份为amount并返回
     *
     * @param date
     * @param amount 从1开始
     * @return
     */
    public static Date setMonths(Date date, int amount) {
        return set(date, Calendar.MONTH, amount - 1);
    }

    /**
     * 重置日期的年份为amount并返回
     *
     * @param date
     * @param amount 从1开始
     * @return
     */
    public static Date setYears(Date date, int amount) {
        return set(date, Calendar.YEAR, amount);
    }

    /**
     * 重围日期的 年份/月份/日期/小时/分钟/秒 为amount的时间
     *
     * @param date   传入的时间
     * @param fileds 年份/月份/日期/小时/分钟/秒
     * @param value  间隔时间
     * @return java.util.Date
     */
    private static Date set(Date date, int fileds, int value) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(fileds, value);
        return calendar.getTime();
    }

    public static String format(Date date, String fmt) {
        return getDateFormat(fmt).format(date);
    }

    public static Date parse(String date, String fmt) {
        try {
            return getDateFormat(fmt).parse(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Date parse(String date) {
        try {
            for (Map.Entry<Pattern, String> entry : regPatternMap.entrySet()) {
                boolean isMatch = entry.getKey().matcher(date).matches();
                if (isMatch) {
                    return getDateFormat(entry.getValue()).parse(date);
                }
            }
        } catch (ParseException e) {
            throw new IllegalArgumentException("can't support this pattern , date is " + date);
        }
        throw new IllegalArgumentException("can't support this pattern , date is " + date);
    }

    public static Date parseYMD(String date) {
        try {
            return getDateFormat(YMD).parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Date parseYMD_HMS(String date) {
        try {
            return getDateFormat(YMD_HMS).parse(date);
        } catch (ParseException e) {
            throw new IllegalArgumentException("the date pattern is error!");
        }
    }

    /**
     * 是否是同一天
     *
     * @param date
     * @param date2
     * @return
     */
    public static boolean isSameDay(Date date, Date date2) {
        if (date == null || date2 == null) {
            return false;
        }
        DateFormat df = getDateFormat(YMD);
        return df.format(date).equals(df.format(date2));
    }

    public static int getHour(Date date) {
        String hour = getDateFormat("HH").format(date);
        return Integer.valueOf(hour);
    }

    public static Date clone(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getTime();
    }

    public static Date getMaxDate(Date date1, Date date2) {
        if (date1.after(date2)) {
            return date1;
        } else {
            return date2;
        }
    }

    public static Date getMinDate(Date date1, Date date2) {
        if (date1.after(date2)) {
            return date2;
        } else {
            return date1;
        }
    }

    /**
     * 根据传入的日期，返回当日最晚时间,形如2013-10-10 23:59:59
     *
     * @param date 日期
     * @return java.util.Date
     */
    public static Date getDateEnd(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取传入日期的最早时间，形如2013-10-10 00:00:00
     *
     * @param date 传入日期
     * @return java.util.Date
     */
    public static Date getDateStart(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    public static Date getDateStart(Date date,int days) {
        date=addDay(date,days);
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取给定日期所在月份的第一天的0点0分0秒
     *
     * @param date 给定日期
     * @return java.util.Date
     */
    public static Date getMonthStart(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 获取给定日期所在月份的第一天的0点0分0秒
     *
     * @param date 给定日期
     * @return java.util.Date
     */
    public static Date getMonthEnd(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        return c.getTime();
    }

    /**
     * yyyy-MM-dd_HH:mm:ss
     *
     * @return
     */
    public static String toUnderlinedString(Date date) {
        return formatYMD_HMS(date).replace(' ', '_');
    }

    public static String removeTime(String datetime) {
        return datetime.substring(0, 10);
    }

}
